﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Globalization;

namespace devtm.Verbatim.CustomConverters
{


    public class Converters
    {

        internal Hashtable container = new Hashtable();

        #region Converters
        
        public TTarget Convert<TSource, TTarget>(TSource source)
        {

            Func<TSource, object, CultureInfo, TTarget> c = null;
            if (GetConverter<TSource, TTarget>(out c))
            {
                return c(source, null, System.Globalization.CultureInfo.CurrentCulture);
            }

            return default(TTarget);

        }

        public TTarget Convert<TSource, TTarget>(TSource source, object parameters)
        {

            Func<TSource, object, CultureInfo, TTarget> c = null;
            if (GetConverter<TSource, TTarget>(out c))
            {
                return c(source, parameters, System.Globalization.CultureInfo.CurrentCulture);
            }

            return default(TTarget);

        }

        public TTarget Convert<TSource, TTarget>(TSource source, object parameters, CultureInfo culture)
        {

            Func<TSource, object, CultureInfo, TTarget> c = null;
            if (GetConverter<TSource, TTarget>(out c))
            {
                return c(source, parameters, culture);
            }

            return default(TTarget);

        }

        #endregion

        private bool GetConverter<TSource, TTarget>(out Func<TSource, object, CultureInfo, TTarget> converter)
        {

            Type t = typeof(IConverter<TSource, TTarget>);
            if (container.ContainsKey(t))
            {
                converter = container[t] as Func<TSource, object, CultureInfo, TTarget>;
                return true;
            }
            else
            {
                converter = null;
                return false;
            }
    
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Converter&lt;TSource, TTarget&gt;"/> class.
        /// </summary>
        /// <typeparam name="TSource">The type of the source.</typeparam>
        /// <typeparam name="TTarget">The type of the target.</typeparam>
        /// <param name="converter">The converter.</param>
        public void Register<TSource, TTarget>(IConverter<TSource, TTarget> converter)
        {

            Type FingerPrint = typeof(IConverter<TSource, TTarget>);
            Type FingerPrintBack = typeof(IConverter<TTarget, TSource>);

            if (!container.ContainsKey(FingerPrint))
            {
                Func<TSource, object, CultureInfo, TTarget> ConvertFunc = (source, parameter, culture) => converter.Convert(source, parameter, culture);
                container.Add(FingerPrint, ConvertFunc);
            }

            if (!container.ContainsKey(FingerPrintBack))
            {
                Func<TTarget, object, CultureInfo, TSource> ConvertFuncBack = (source, parameter, culture) => converter.ConvertBack(source, parameter, culture);
                container.Add(FingerPrintBack, ConvertFuncBack);
            }
            
        }

    }


    public abstract class Converter<TSource, TTarget> : IConverter<TSource, TTarget>
    {

         

        /// <summary>
        /// Initializes a new instance of the <see cref="Converter&lt;TSource, TTarget&gt;"/> class.
        /// </summary>
        public Converter()
        {
        }


        /// <summary>
        /// Gets the type of the source. 
        /// </summary>
        /// <returns></returns>
        public static Type GetSourceType()
        {
            return typeof(TSource);
        }

        /// <summary>
        /// Gets the type of the target.
        /// </summary>
        /// <returns></returns>
        public static Type GetTargetType()
        {
            return typeof(TTarget);
        }


        /// <summary>
        /// Converts the specified value.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        public TTarget Convert(TSource value)
        {
            return Convert(value, null, System.Globalization.CultureInfo.CurrentCulture);
        }

        /// <summary>
        /// Converts the specified value.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="parameter">The parameter.</param>
        /// <returns></returns>
        public TTarget Convert(TSource value, object parameter)
        {
            return Convert(value, parameter, System.Globalization.CultureInfo.CurrentCulture);
        }

        /// <summary>
        /// Converts the specified value.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="parameter">The parameter.</param>
        /// <param name="culture">The culture.</param>
        /// <returns></returns>
        public abstract TTarget Convert(TSource value, object parameter, System.Globalization.CultureInfo culture);


        /// <summary>
        /// Converts the specified value.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        public TSource ConvertBack(TTarget value)
        {
            return ConvertBack(value, null, System.Globalization.CultureInfo.CurrentCulture);
        }

        /// <summary>
        /// Converts the specified value.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="parameter">The parameter.</param>
        /// <returns></returns>
        public TSource ConvertBack(TTarget value, object parameter)
        {
            return ConvertBack(value, parameter, System.Globalization.CultureInfo.CurrentCulture);
        }
        public abstract TSource ConvertBack(TTarget value, object parameter, System.Globalization.CultureInfo culture);


    }


}
